import pandas as pd
import numpy as np
import os
import tkinter as tk
from tkinter import filedialog, messagebox, simpledialog
import logging
from datetime import datetime
import shutil
import pandas as pd
import openpyxl
from openpyxl.utils import get_column_letter

# 配置日志
logging.basicConfig(
    level=logging.INFO,
    format='%(asctime)s - %(levelname)s - %(message)s',
    handlers=[
        logging.FileHandler("excel_search_tool.log"),
        logging.StreamHandler()
    ]
)

class ExcelSearchTool:
    def __init__(self):
        self.root = tk.Tk()
        self.root.title("Excel搜索工具")
        self.root.geometry("600x400")
        self.root.resizable(True, True)
        
        # 设置中文字体
        self.font_config = ("SimHei", 10)
        
        # 源文件路径
        self.source_file_path = "D:/VaultView/SOLIDWORKS数据管理/5-Giant-laser工作体系/非质量管理体系文件/业务部/瀚越已发货包装数据总表.xlsx"
        
        # 搜索结果数据
        self.all_results = []
        self.search_text = ""
        self.search_count = 0
        
        # 创建GUI
        self.create_widgets()
        
        # 验证源文件路径
        self.validate_source_path()
        
    def create_widgets(self):
        # 创建主框架
        main_frame = tk.Frame(self.root)
        main_frame.pack(fill=tk.BOTH, expand=True, padx=10, pady=10)
        
        # 源文件路径显示
        path_frame = tk.Frame(main_frame)
        path_frame.pack(fill=tk.X, pady=(0, 10))
        
        tk.Label(path_frame, text="源文件路径:", font=self.font_config).pack(side=tk.LEFT)
        self.path_var = tk.StringVar(value=self.source_file_path)
        path_entry = tk.Entry(path_frame, textvariable=self.path_var, width=50, font=self.font_config)
        path_entry.pack(side=tk.LEFT, fill=tk.X, expand=True, padx=(5, 5))
        
        tk.Button(path_frame, text="浏览", command=self.browse_source_file, font=self.font_config).pack(side=tk.RIGHT)
        
        # 状态显示区域
        status_frame = tk.Frame(main_frame)
        status_frame.pack(fill=tk.BOTH, expand=True)
        
        tk.Label(status_frame, text="操作日志:", font=self.font_config).pack(anchor=tk.W)
        
        # 日志文本框
        self.log_text = tk.Text(status_frame, height=15, font=self.font_config)
        self.log_text.pack(fill=tk.BOTH, expand=True, pady=(5, 5))
        scrollbar = tk.Scrollbar(self.log_text, command=self.log_text.yview)
        scrollbar.pack(side=tk.RIGHT, fill=tk.Y)
        self.log_text.config(yscrollcommand=scrollbar.set)
        
        # 按钮区域
        button_frame = tk.Frame(main_frame)
        button_frame.pack(fill=tk.X, pady=(10, 0))
        
        tk.Button(button_frame, text="开始搜索", command=self.start_search, font=self.font_config, width=15).pack(side=tk.LEFT)
        tk.Button(button_frame, text="退出", command=self.root.quit, font=self.font_config, width=15).pack(side=tk.RIGHT)
        
    def browse_source_file(self):
        file_path = filedialog.askopenfilename(
            title="选择源Excel文件",
            filetypes=[("Excel files", "*.xlsx;*.xls")]
        )
        if file_path:
            self.source_file_path = file_path
            self.path_var.set(file_path)
            self.validate_source_path()
    
    def validate_source_path(self):
        try:
            # 打印路径信息进行调试
            self.log(f"===== 源文件路径验证 =====")
            self.log(f"读取到的路径值: {self.source_file_path}")
            self.log(f"路径长度: {len(self.source_file_path)} 字符")
            
            # 检查路径是否为空
            if not self.source_file_path:
                self.log("错误: 源文件路径未设置", level="error")
                return False
            
            # 检查文件是否存在
            if not os.path.exists(self.source_file_path):
                self.log(f"错误: 源文件不存在! 路径: {self.source_file_path}", level="error")
                return False
            
            # 检查文件是否为Excel文件
            ext = os.path.splitext(self.source_file_path)[1].lower()
            if ext not in ['.xlsx', '.xls']:
                self.log(f"错误: 文件不是有效的Excel文件! 路径: {self.source_file_path}", level="error")
                return False
            
            # 尝试打开文件验证
            try:
                df = pd.read_excel(self.source_file_path, sheet_name="已发货", nrows=5)
                self.log("源文件验证成功!")
                return True
            except Exception as e:
                self.log(f"错误: 无法打开或读取源文件! 错误信息: {str(e)}", level="error")
                return False
        except Exception as e:
            self.log(f"路径验证过程中发生错误: {str(e)}", level="error")
            return False
    
    def log(self, message, level="info"):
        # 添加到日志文本框
        timestamp = datetime.now().strftime("%H:%M:%S")
        log_message = f"[{timestamp}] {message}\n"
        self.log_text.insert(tk.END, log_message)
        self.log_text.see(tk.END)
        
        # 记录到日志文件
        if level == "info":
            logging.info(message)
        elif level == "error":
            logging.error(message)
        elif level == "warning":
            logging.warning(message)
    
    def start_search(self):
        # 验证源文件路径
        if not self.validate_source_path():
            messagebox.showerror("错误", "源文件路径无效，请检查路径设置!")
            return
        
        # 重置搜索结果
        self.all_results = []
        self.search_count = 0
        
        # 开始搜索循环
        self.continue_search()
    
    def continue_search(self):
        # 询问是否继续搜索
        if self.search_count > 0:
            result = messagebox.askyesno("搜索工具", "是否继续搜索？")
            if not result:
                self.finalize_results()
                return
        
        # 执行单次搜索
        self.perform_single_search()
    
    def perform_single_search(self):
        try:
            self.search_count += 1
            search_text = simpledialog.askstring("搜索设置", f"请输入第 {self.search_count} 次搜索的文本：")
            
            # 检查是否取消搜索
            if search_text is None:
                if self.search_count == 1:
                    self.log("搜索已取消")
                else:
                    self.finalize_results()
                return
            
            # 检查搜索文本是否为空
            search_text = search_text.strip()
            if not search_text:
                messagebox.showinfo("信息", "未输入搜索内容，本次搜索取消")
                self.continue_search()
                return
            
            self.log(f"开始第 {self.search_count} 次搜索，搜索文本: '{search_text}'")
            
            # 使用openpyxl读取Excel文件以支持合并单元格
            try:
                # 打开工作簿
                wb = openpyxl.load_workbook(self.source_file_path, data_only=True)
                sheet = wb["已发货"]
                
                # 获取表头
                headers = []
                for col in range(1, sheet.max_column + 1):
                    headers.append(sheet.cell(row=1, column=col).value)
                
                # 记录已处理的行
                processed_rows = set()
                results = []
                
                # 遍历所有行（跳过表头）
                for row in range(2, sheet.max_row + 1):
                    # 跳过已处理的行
                    if row in processed_rows:
                        continue
                    
                    # 获取B列单元格的值
                    cell_b = sheet.cell(row=row, column=2)  # B列是第2列
                    cell_value = cell_b.value
                    
                    # 检查是否包含搜索文本
                    if cell_value and isinstance(cell_value, str) and search_text.lower() in cell_value.lower():
                        # 检查E列是否为合并单元格
                        cell_e = sheet.cell(row=row, column=5)  # E列是第5列
                        
                        # 查找该单元格所属的合并区域
                        merge_range = None
                        for merge in sheet.merged_cells.ranges:
                            if cell_e.coordinate in merge:
                                merge_range = merge
                                break
                        
                        # 确定要复制的行范围
                        if merge_range:
                            start_row = merge_range.min_row
                            end_row = merge_range.max_row
                        else:
                            start_row = row
                            end_row = row
                        
                        # 添加到结果
                        for r in range(start_row, end_row + 1):
                            if r not in processed_rows:
                                row_data = []
                                for col in range(1, sheet.max_column + 1):
                                    row_data.append(sheet.cell(row=r, column=col).value)
                                results.append(row_data)
                                processed_rows.add(r)
                
                # 创建DataFrame
                if results:
                    search_results = pd.DataFrame(results, columns=headers)
                    # 添加搜索文本标识
                    search_results.insert(0, "搜索文本", search_text)
                    self.all_results.append(search_results)
                    self.log(f"搜索完成，找到 {len(search_results)} 条匹配记录")
                    messagebox.showinfo("信息", f"第 {self.search_count} 次搜索完成，找到 {len(search_results)} 条记录")
                else:
                    self.log("搜索完成，未找到匹配记录")
                    messagebox.showinfo("信息", f"第 {self.search_count} 次搜索无结果")
                    
                # 关闭工作簿
                wb.close()
                
            except Exception as e:
                self.log(f"读取Excel文件时发生错误: {str(e)}", level="error")
                messagebox.showerror("错误", f"读取Excel文件时发生错误: {str(e)}")
            
            # 继续下一次搜索
            self.continue_search()
            
        except Exception as e:
            self.log(f"搜索过程中发生错误: {str(e)}", level="error")
            messagebox.showerror("错误", f"搜索过程中发生错误: {str(e)}")
            
    def finalize_results(self):
        try:
            if not self.all_results:
                self.log("未执行任何搜索")
                messagebox.showinfo("信息", "未执行任何搜索")
                return
            
            # 按照VBA格式组织结果
            self.log("正在按照VBA格式组织搜索结果...")
            
            # 保存结果
            self.save_results_vba_format()
            
            self.log("所有操作完成")
            messagebox.showinfo("信息", "所有操作完成")
            
        except Exception as e:
            self.log(f"处理结果时发生错误: {str(e)}", level="error")
            messagebox.showerror("错误", f"处理结果时发生错误: {str(e)}")
    
    def save_results(self, df):
        try:
            # 获取桌面路径
            desktop_path = os.path.join(os.path.expanduser("~"), "Desktop")
            
            # 生成唯一文件名
            base_filename = "整合搜索结果.xlsx"
            save_path = os.path.join(desktop_path, base_filename)
            
            # 检查文件是否存在，如果存在则添加数字后缀
            counter = 1
            while os.path.exists(save_path):
                save_path = os.path.join(desktop_path, f"整合搜索结果_{counter}.xlsx")
                counter += 1
            
            # 保存为Excel文件
            df.to_excel(save_path, index=False)
            
            self.log(f"结果已保存至: {save_path}")
            messagebox.showinfo("信息", f"结果已保存至：\n{save_path}")
            
        except Exception as e:
            self.log(f"保存结果时发生错误: {str(e)}", level="error")
            messagebox.showerror("错误", f"保存结果时发生错误: {str(e)}")
    
    def save_results_vba_format(self):
        """按照VBA格式保存搜索结果，保留合并单元格格式"""
        try:
            # 获取桌面路径
            desktop_path = os.path.join(os.path.expanduser("~"), "Desktop")
            
            # 生成唯一文件名
            base_filename = "整合搜索结果.xlsx"
            save_path = os.path.join(desktop_path, base_filename)
            
            # 检查文件是否存在，如果存在则添加数字后缀
            counter = 1
            while os.path.exists(save_path):
                save_path = os.path.join(desktop_path, f"整合搜索结果_{counter}.xlsx")
                counter += 1
            
            # 创建一个新的工作簿
            wb = openpyxl.Workbook()
            ws = wb.active
            ws.title = "搜索结果"
            
            # 当前写入行
            current_row = 1
            
            # 再次打开源文件以获取合并单元格信息
            source_wb = openpyxl.load_workbook(self.source_file_path)
            source_sheet = source_wb["已发货"]
            
            # 遍历所有搜索结果
            for i, search_df in enumerate(self.all_results):
                # 检查是否有搜索结果
                if len(search_df) > 0:
                    # 获取搜索文本（从DataFrame的第一列获取）
                    search_text = search_df.iloc[0, 0]
                    
                    # 在结果前添加标题行，格式为"搜索文本: [搜索内容]"
                    ws.cell(row=current_row, column=1).value = f"搜索文本: {search_text}"
                    # 设置标题行格式（加粗、12号字体）
                    title_font = openpyxl.styles.Font(bold=True, size=12)
                    ws.cell(row=current_row, column=1).font = title_font
                    current_row += 1
                    
                    # 移除DataFrame中的搜索文本列
                    result_df = search_df.drop(columns=["搜索文本"])
                    
                    # 获取表头
                    headers = result_df.columns.tolist()
                    
                    # 写入表头
                    for col_idx, header in enumerate(headers, start=1):
                        ws.cell(row=current_row, column=col_idx).value = header
                        # 设置表头格式
                        ws.cell(row=current_row, column=col_idx).font = openpyxl.styles.Font(bold=True)
                    current_row += 1
                    
                    # 创建一个字典来存储源文件中的合并单元格信息
                    # key: (行, 列) 作为参考点，value: (合并区域的行数, 合并区域的列数)
                    merge_info = {}
                    for merge in source_sheet.merged_cells.ranges:
                        # 记录合并区域的信息
                        start_row = merge.min_row
                        end_row = merge.max_row
                        start_col = merge.min_col
                        end_col = merge.max_col
                        merge_info[(start_row, start_col)] = (end_row - start_row + 1, end_col - start_col + 1)
                    
                    # 写入数据并尝试恢复合并单元格格式
                    for _, row_data in result_df.iterrows():
                        # 记录当前行在结果中的位置
                        result_row = current_row
                        
                        # 写入行数据
                        for col_idx, value in enumerate(row_data, start=1):
                            ws.cell(row=current_row, column=col_idx).value = value
                        
                        # 检查当前行是否有合并单元格
                        # 注意：这里我们只能根据源文件中的合并模式来尝试恢复
                        # 由于我们不知道具体哪些行在原始文件中是合并的，所以这是一个近似实现
                        # 在实际使用中，可能需要更复杂的逻辑来准确识别匹配行的合并模式
                        
                        # 特别处理用户提到的三列：包装箱外尺寸、重量、包装箱
                        # 这些列在数据源中是合并的，我们需要确保它们在结果中也被合并
                        box_dimensions_col = None
                        weight_col = None
                        packaging_col = None
                        
                        for idx, header in enumerate(headers):
                            if "包装箱外尺寸" in str(header):
                                box_dimensions_col = idx + 1
                            elif "重量" in str(header):
                                weight_col = idx + 1
                            elif "包装箱" in str(header):
                                packaging_col = idx + 1
                        
                        # 对于这些特定列，我们假设它们在原始数据中是合并的
                        # 在实际应用中，可能需要根据实际情况调整
                        
                        current_row += 1
                    
                    # 完成数据写入后，我们需要分析并创建合并单元格
                    # 这里我们检查连续的相同值行，将它们合并
                    # 这是一个简单的启发式方法，实际应用中可能需要更复杂的逻辑
                    
                    # 对于用户特别提到的三列，我们尝试合并具有相同值的连续行
                    for target_col in [box_dimensions_col, weight_col, packaging_col]:
                        if target_col:
                            # 检查结果区域中的行数
                            result_rows = current_row - (result_df.shape[0] + 1)  # +1 是因为包括了表头
                            
                            # 如果有足够的行，尝试识别和合并单元格
                            if result_rows > 1:
                                start_merge_row = None
                                current_value = None
                                
                                for r in range(result_row, current_row):
                                    cell_value = ws.cell(row=r, column=target_col).value
                                    
                                    if cell_value == current_value and cell_value is not None:
                                        # 相同值，继续合并区域
                                        pass
                                    else:
                                        # 值不同，结束之前的合并区域（如果有）
                                        if start_merge_row and start_merge_row < r - 1:
                                            ws.merge_cells(start_row=start_merge_row, start_column=target_col,
                                                           end_row=r - 1, end_column=target_col)
                                        
                                        # 开始新的合并区域
                                        start_merge_row = r
                                        current_value = cell_value
                                
                                # 处理最后一个合并区域
                                if start_merge_row and start_merge_row < current_row - 1:
                                    ws.merge_cells(start_row=start_merge_row, start_column=target_col,
                                                   end_row=current_row - 1, end_column=target_col)
                    
                    # 添加空行分隔不同的搜索结果
                    current_row += 1
                else:
                    # 如果没有搜索结果，添加"无匹配"文本并设置红色字体
                    ws.cell(row=current_row, column=1).value = "无匹配"
                    no_match_font = openpyxl.styles.Font(color="FF0000")  # 红色
                    ws.cell(row=current_row, column=1).font = no_match_font
                    current_row += 2  # +2 是为了添加空行
            
            # 自动调整列宽
            for col in ws.columns:
                max_length = 0
                column = get_column_letter(col[0].column)  # 获取列字母
                for cell in col:
                    try:
                        if cell.value and len(str(cell.value)) > max_length:
                            max_length = len(str(cell.value))
                    except:
                        pass
                adjusted_width = (max_length + 2)  # +2 是为了添加一些边距
                ws.column_dimensions[column].width = adjusted_width
            
            # 保存工作簿
            wb.save(save_path)
            source_wb.close()
            
            self.log(f"结果已按照VBA格式保存至: {save_path}")
            messagebox.showinfo("信息", f"结果已按照VBA格式保存至：\n{save_path}")
            
        except Exception as e:
            self.log(f"按照VBA格式保存结果时发生错误: {str(e)}", level="error")
            messagebox.showerror("错误", f"按照VBA格式保存结果时发生错误: {str(e)}")

    def run(self):
        self.root.mainloop()

if __name__ == "__main__":
    try:
        # 创建并运行应用
        app = ExcelSearchTool()
        app.run()
    except Exception as e:
        logging.error(f"应用程序发生未处理异常: {str(e)}")
        messagebox.showerror("错误", f"应用程序发生错误: {str(e)}")